//
// Created by Administrator on 2020/5/25.
//
#include <stdlib.h>
#include <string.h>

#include "zcb.h"
#include "zm32_ap.h"
#include "zm32_statemachine.h"
#include "debug.h"
#include "utils.h"
#include "zm32_message.h"

condition_val_ts read_conf, write_conf, nwking;
condition_val_ts nwking_state, tx_cnf, rx_cnf, join;

static state_cmd_te state;
static struct conf_info dev_config;

int zcb_init( void )
{
    utils_cond_init(&read_conf);
    utils_cond_init(&write_conf);
    utils_cond_init(&nwking);
    utils_cond_init(&nwking_state);
    utils_cond_init(&tx_cnf);
    utils_cond_init(&rx_cnf);
    utils_cond_init(&join);
    return 0;
}

int zcb_destroy( void )
{
    utils_cond_destroy(&read_conf);
    utils_cond_destroy(&write_conf);
    utils_cond_destroy(&nwking);
    utils_cond_destroy(&nwking_state);
    utils_cond_destroy(&tx_cnf);
    utils_cond_destroy(&rx_cnf);
    utils_cond_destroy(&join);
    return 0;
}


int zcb_networking_start( void )
{
    while ( 1 )
    {
        switch ( state )
        {
            case EN_STATE_CMD_GET_CONFIG_REQ:
            {
                zm32_get_local_config_req();
                state = EN_STATE_CMD_WAIT_GET_CONFIG_RESP;
                break;
            }

            case EN_STATE_CMD_WAIT_GET_CONFIG_RESP:
            {
                if ( EN_UTILS_OK == utils_cond_wait_until(&read_conf, 1000) )
                {
                    LOGI("read_conf");
                    struct pstloc_conf_read_resp *resp;
                    resp = (struct pstloc_conf_read_resp *) read_conf.val;

                    memcpy(&dev_config, &resp->config, sizeof(struct conf_info));
                    if (resp->state == EN_R_STATE_SETED)
                    {
                        if (resp->config.role != EN_DEV_ROLE_COORDINATOR)
                        {
                            LOGI("device role:%d", resp->config.role);
                            state = EN_STATE_CMD_LOAD_DEF_CONFIG_REQ;
                        }
                        else
                        {
                            if ( resp->config.panid != 0xFFFF )
                            {
                                LOGI("PAN ID:%04X", resp->config.panid);
                                state = EN_STATE_CMD_FINISH;
                            }
                            else
                            {
                                LOGI("PAN isn't create");
                                state = EN_STATE_CMD_SET_NWKING_MODE_REQ;
                            }
                        }
                    }
                    else if ( resp->state == EN_R_STATE_SETTING )
                    {
                        state = EN_STATE_CMD_RESET_REQ;
                    }
                    else if ( resp->state == EN_R_STATE_OTA_MODE )
                    {

                    }
                    else
                    {
                        state = EN_STATE_CMD_RESET_REQ;
                    }

                    free(read_conf.val);
                    read_conf.val = NULL;
                }
                else
                {
                    state = EN_STATE_CMD_GET_CONFIG_REQ;
                }
                break;
            }

            case EN_STATE_CMD_LOAD_DEF_CONFIG_REQ:
            {
                struct pstnwk_set_remote_conf_req req;

                LOGI("dev_config.nwkaddr:%04X", dev_config.nwkaddr);
                req.nwkaddr = dev_config.nwkaddr;
                dev_config.role = EN_DEV_ROLE_COORDINATOR;
                //dev_config.txmode
                memcpy(&req.config, &dev_config, sizeof(struct conf_info));

                zm32_set_remote_config_req(&req);
                state = EN_STATE_CMD_WAIT_LOAD_DEF_CONFIG_RESP;
                break;
            }

            case EN_STATE_CMD_WAIT_LOAD_DEF_CONFIG_RESP:
            {
                if ( EN_UTILS_OK != utils_cond_wait_until(&write_conf, 1000) )
                {
                    state = EN_STATE_CMD_LOAD_DEF_CONFIG_REQ;
                }
                else
                {
                    struct pstnwk_set_remote_conf_resp *resp = (struct pstnwk_set_remote_conf_resp *) write_conf.val;

                    LOGI("nwkaddr:%04X state:%X", resp->nwkaddr, resp->state);
                    free(write_conf.val);
                    write_conf.val = NULL;
                    state = EN_STATE_CMD_RESET_REQ;
                }
                break;
            }

            case EN_STATE_CMD_SET_NWKING_MODE_REQ:
            {
                zm32_networking_node_req(EN_DEV_ROLE_COORDINATOR, EN_OPT_WRITE, EN_NWKING_MODE_AUTO);
                state = EN_STATE_CMD_WAIT_SET_NWKING_MODE_RESP;
                break;
            }

            case EN_STATE_CMD_WAIT_SET_NWKING_MODE_RESP:
            {
                if ( EN_UTILS_OK != utils_cond_wait_until(&nwking, 2000) )
                {
                    state = EN_STATE_CMD_SET_NWKING_MODE_REQ;
                }
                else
                {
                    struct pstloc_join_mode_resp *resp = (struct pstloc_join_mode_resp *) nwking.val;
                    LOGI("role:%X mode:%X state:%X", resp->role, resp->mode, resp->state);
                    free(nwking.val);
                    nwking.val = NULL;
                    state = EN_STATE_CMD_NWKING_RESET_REQ;
                }
                break;
            }

            case EN_STATE_CMD_NWKING_RESET_REQ:
            {
                zm32_reset_remote_req(dev_config.nwkaddr, ZM32_PROTO_TYPE);
                sleep(2);
                state = EN_STATE_CMD_NWKING_STATE_REQ;
                break;
            }

            case EN_STATE_CMD_NWKING_STATE_REQ:
            {
                zm32_get_networking_state_req();
                state = EN_STATE_CMD_NWKING_STATE_RESP;
                break;
            }

            case EN_STATE_CMD_NWKING_STATE_RESP:
            {
                if ( EN_UTILS_OK != utils_cond_wait_until(&nwking_state, 2000) )
                {
                    state = EN_STATE_CMD_NWKING_STATE_REQ;
                }
                else
                {
                    struct pstloc_get_module_status_resp *resp = ( struct pstloc_get_module_status_resp * ) nwking_state.val;
                    if ( resp->state != 0 )
                    {
                        LOGE("resp state error");
                        state = EN_STATE_CMD_NWKING_STATE_REQ;
                    }
                    else
                    {
                        if ( resp->status == EN_NWKING_ST_BUSY )
                        {
                            LOGI("The network has not yet been created");
                            sleep(1);
                            state = EN_STATE_CMD_NWKING_STATE_REQ;
                        }
                        else
                        {
                            state = EN_STATE_CMD_GET_CONFIG_REQ;
                        }
                    }
                    free(nwking_state.val);
                    nwking_state.val = NULL;
                }
                break;
            }

            case EN_STATE_CMD_RESET_REQ:
            {
                zm32_reset_remote_req(dev_config.nwkaddr, ZM32_PROTO_TYPE);
                sleep(2);
                state = EN_STATE_CMD_GET_CONFIG_REQ;
                break;
            }

            case EN_STATE_CMD_FINISH:
            {
                return 0;
                break;
            }

            default:
                break;
        }
    }
}


int zcb_rxtx_mode_set(void)
{
    unsigned char stat;


    while (1) {
        zm32_tmploc_tx_mode_req(0, 0, 1, 3);
        if ( EN_UTILS_OK != utils_cond_wait_until(&tx_cnf, 2000) ) {
            if (tx_cnf.val) {
                free(tx_cnf.val);
                tx_cnf.val = NULL;
            }
            continue;
        }
        struct tmploc_set_tx_mode_resp *resp = (struct tmploc_set_tx_mode_resp *)tx_cnf.val;
        stat = resp->state;
        free(tx_cnf.val);
        tx_cnf.val = NULL;
        if (!stat)
            break;
    }

    while (1) {
        zm32_tmpmac_rx_mode_req(dev_config.macaddr, 4);
        if ( EN_UTILS_OK != utils_cond_wait_until(&rx_cnf, 2000) ) {
            if (rx_cnf.val) {
                free(rx_cnf.val);
                rx_cnf.val = NULL;
            }
            continue;
        }
        struct tmpmac_set_rx_mode_resp *resp = ( struct tmpmac_set_rx_mode_resp *)rx_cnf.val;
        stat = resp->state;
        printf("stat = %d\n", stat);
        free(rx_cnf.val);
        rx_cnf.val = NULL;
        if (!stat)
            break;
    }

    return 0;
}

int nwk_join_perm(unsigned short dur)
{
    unsigned char stat;

    if (zm32_permit_join_req(dur) != 0)
        return -1;
    if (utils_cond_wait_until(&join, 2000) != EN_UTILS_OK)
        return -2;
    struct pstloc_permit_join_resp *resp = (struct pstloc_permit_join_resp *)join.val;
    stat = resp->state;
    free(join.val);
    join.val = NULL;

    if (stat != 0)
        return -3;

    return 0;
}
